package com.sqlsession.database;

import com.sqlsession.DataBase;
import com.sqlsession.DateSource;
import com.sqlsession.filter.DbFilter;

import java.sql.*;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public abstract class BaseDateSource implements DateSource {
    private DataBase dataBase;
    private Connection connection;
    private DbFilter filter;

    public BaseDateSource(DataBase dataBase) {
        this.dataBase = dataBase;
        filter = dataBase.getDbFilter();
    }

    public final DataBase getDataBase() {
        return dataBase;
    }

    protected final DbFilter getFilter() {
        return filter;
    }

    @Override
    public List<CTable> getSelectTablesSql(ResultSet resultSet) throws SQLException {
        List<CTable> cTables = new LinkedList<>();
        if (resultSet == null) {
            Connection connection = getConnection();
            DatabaseMetaData dbmd = connection.getMetaData();
            String catalog = connection.getCatalog();
            String name = dataBase.getName();
            resultSet = dbmd.getTables(catalog, name, null, new String[]{"TABLE"});
        }
        while (resultSet.next()) {
            String remarks = resultSet.getString("REMARKS");
            String table_name = resultSet.getString("TABLE_NAME");
            String tableType = resultSet.getString("TABLE_TYPE");  //表类型
            if (!filter.filterTable(table_name)) {
                continue;
            }
            CTable cTable = new CTable(dataBase);
            cTable.setName(table_name);
            cTable.setCommon(remarks);
            cTables.add(cTable);
        }
        return cTables;
    }

    @Override
    public List<CTable> getSelectTablesSql() throws SQLException {
        return getSelectTablesSql(null);
    }

    @Override
    public List<CColumn> getColumns(CTable cTable) throws SQLException {
        List<CColumn> cColumns = new LinkedList<>();
        Connection connection = getConnection();
        DatabaseMetaData dbmd = connection.getMetaData();
        String catalog = connection.getCatalog();
        String name = cTable.getName();
        ResultSet rs = dbmd.getColumns(catalog, null, name, "%");
        Statement statement = connection.createStatement();
        StringBuilder builder = new StringBuilder("Select col.column_name from all_constraints con,all_cons_columns col where con.constraint_name= col.constraint_name and con.constraint_type='P' and col.table_name= ");
        builder.append("'");
        builder.append(cTable.getName());
        builder.append("'");
        String sql = builder.toString();
        ResultSet resultSet = statement.executeQuery(sql);
        Map<String, Boolean> primaryKeys = new HashMap<>();
        while (resultSet.next()) {
            String primaryKey = resultSet.getString("COLUMN_NAME");
            primaryKeys.put(primaryKey, true);
        }
        resultSet.close();
        statement.close();
        while (rs.next()) {
            String cloumnName = rs.getString("COLUMN_NAME");
            if (!filter.filterColumn(cTable.getName(), cloumnName)) {
                continue;
            }
            String REMARKS = rs.getString("REMARKS");
            String DATA_TYPE = rs.getString("DATA_TYPE"); //对应的java.sql.Types的SQL类型(列类型ID)
            int COLUMN_SIZE = rs.getInt("COLUMN_SIZE"); //列大小
            int DECIMAL_DIGITS = rs.getInt("DECIMAL_DIGITS"); //小数位数
            int numPrecRadix = rs.getInt("NUM_PREC_RADIX");  //基数（通常是10或2） --未知
            String SQL_DATA_TYPE = rs.getString("SQL_DATA_TYPE");
            String SQL_DATETIME_SUB = rs.getString("SQL_DATETIME_SUB");
            String CHAR_OCTET_LENGTH = rs.getString("CHAR_OCTET_LENGTH");// 对于 char 类型，该长度是列中的最大字节数
            String ORDINAL_POSITION = rs.getString("ORDINAL_POSITION");
            String TYPE_NAME = rs.getString("TYPE_NAME"); //java.sql.Types类型名称(列类型名称)
            String IS_NULLABLE = rs.getString("IS_NULLABLE");
            String SCOPE_CATLOG = rs.getString("SCOPE_CATLOG");
            int nullAble = rs.getInt("NULLABLE");  //是否允许为null
            String columnDef = rs.getString("COLUMN_DEF");  //默认值
            boolean yes = primaryKeys.get(cloumnName) != null;//IS_NULLABLE.equals("YES");

            CColumn cColumn = new CColumn(cTable);
            cColumn.setCommon(REMARKS);
            cColumn.setName(cloumnName);
            cColumn.primaryKey(yes);
            cColumn.setType(TYPE_NAME);
            cColumn.setLength(COLUMN_SIZE);
            cColumns.add(cColumn);
        }
        rs.close();
        return cColumns;
    }

    @Override
    public Connection getConnection() {
        try {
            if (connection != null && !connection.isClosed()) {
                return connection;
            }
            connection = DriverManager.getConnection(getUrl(), dataBase.getUser(), dataBase.getPassword());
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return connection;
    }


    public abstract String getUrl();


    @Override
    public void close() {
        try {
            if (connection != null) {
                connection.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
